JBoss Community Archive (Read Only)

Errai

Alternatives and Mocks

Alternatives

It may be desirable to have multiple matching dependencies for a given injection point with the ability to specify which implementation to use at runtime. For instance, you may have different versions of your application which target different browsers or capabilities of the browser. Using alternatives allows you to share common interfaces among your beans, while still using dependency injection, by exporting consideration of what implementation to use to the container's configuration.

Consider the following example:

@Singleton @Alternative
public class MobileView implements View {
  // ... //
}

and

@Singleton @Alternative
public class DesktopView implements View {
  // ... // 

In our controller logic we in turn inject the View interface:

@EntryPoint
public class MyApp {
  @Inject
  View view;
  
  // ... //
}

This code is unaware of the implementation of View, which maintains good separation of concerns. However, this of course creates an ambiguous dependency on the View interface as it has two matching subtypes in this case. Thus, we must configure the container to specify which alternative to use. Also note, that the beans in both cases have been annotated with javax.enterprise.inject.Alternative.

In your ErraiApp.properties for the module, you can simply specify which active alternative should be used:

errai.ioc.enabled.alternatives=org.foo.MobileView

You can specify multiple alternative classes by white space separating them:

errai.ioc.enabled.alternatives=org.foo.MobileView \
                               org.foo.HTML5Orientation \
                               org.foo.MobileStorage 

You can only have one enabled alternative for a matching set of alternatives, otherwise you will get ambiguous resolution errors from the container.

Test Mocks

Similar to alternatives, but specifically designed for testing scenarios, you can replace beans with mocks at runtime for the purposes of running unit tests. This is accomplished simply by annotating a bean with the org.jboss.errai.ioc.client.api.TestMock annotation. Doing so will prioritize consideration of the bean over any other matching beans while running unit tests.

Consider the following:

@ApplicationScoped
public class UserManagementImpl implements UserManagement {
  public List<User> listUsers() {
     // do user listy things!
  } 
}

You can specify a mock implementation of this class by implementing its common parent type (UserManagement) and annotating that class with the @TestMock annotation inside your test package like so:

@TestMock @ApplicationScoped
public class MockUserManagementImpl implements UserManagement {
  public List<User> listUsers() { 
     // return only a test user.
     return Collections.singletonList(TestUser.INSTANCE);
  }
}

In this case, the container will replace the UserManagementImpl with the MockUserManagementImpl automatically when running the unit tests.

The @TestMock annotation can also be used to specify alternative providers during test execution. For example, it can be used to mock a Caller<T>. Callers are used to invoke RPC or JAX-RS endpoints. During tests you might want to replace theses callers with mock implementations. For details on providers see Container Wiring.

@TestMock @IOCProvider
public class MockedHappyServiceCallerProvider implements ContextualTypeProvider<Caller<HappyService>> {
 
  @Override
  public Caller<HappyService> provide(Class<?>[] typeargs, Annotation[] qualifiers) {
    return new Caller<HappyService>() {
      ...
    }
}
JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-10 12:34:51 UTC, last content change 2012-09-01 17:50:44 UTC.